#include "bbh_output_file.h"

#include "bbh_include.h"

#include "bbh_output.h"

#ifdef _WIN32
#define FILE_HANDLE FILE*
#else
#define FILE_HANDLE FILE*
#endif

#define MAX_OUTPUT_BUFFER 4*1024

struct bbh_output_file_s
{
    FILE_HANDLE                 fd;
    char                        buf[MAX_OUTPUT_BUFFER];
    //size_t                      len;
};

static int  bbh_output_file_open(const char*s, size_t len, void**pptr)
{
    struct bbh_output_file_s *p;
    const char*filepath = s;

    FILE_HANDLE fd = fopen(filepath, "a");
    if (!fd)
        return -1;
    
    p = (struct bbh_output_file_s*)malloc(sizeof(struct bbh_output_file_s));
    if (!p) {
        fclose(fd);
        return -1;
    }
    memset(p, 0, sizeof(struct bbh_output_file_s));

    p->fd           = fd;
    setvbuf(fd, p->buf, _IOFBF, MAX_OUTPUT_BUFFER);

    *pptr = p;

    return 0;
}
static int  bbh_output_file_write(void*_, const char*s, size_t len)
{
    struct bbh_output_file_s*out = (struct bbh_output_file_s*)_;
    return (int)fwrite(s, 1, len, out->fd);
}

static int  bbh_output_file_print(void*_, const char*fmt, ...)
{
    struct bbh_output_file_s*out = (struct bbh_output_file_s*)_;
    int r = 0;
    va_list ap;
    va_start(ap, fmt);
    r = vfprintf(out->fd, fmt, ap);
    va_end(ap);
    return r;
}

static void bbh_output_file_flush(void*_)
{
    struct bbh_output_file_s*out = (struct bbh_output_file_s*)_; 
    fflush(out->fd);
}

static void bbh_output_file_close(void*_)
{
    struct bbh_output_file_s*out = (struct bbh_output_file_s*)_; 

    fflush(out->fd);
    fclose(out->fd);

    free(out);
}

static struct bbh_output_s output_file_driver = {
    output_type_file,
    "file",
    bbh_output_file_open,
    bbh_output_file_write,
    bbh_output_file_print,
    bbh_output_file_flush,
    bbh_output_file_close
};

struct bbh_output_s*  bbh_output_file_driver()
{
    return &output_file_driver;
}